package org.skywork.top.core.algorithm.num;

import java.util.*;

/**
 * 三数之和
 */
public class no_15 {


    /**
     * 给你一个整数数组 nums ，判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ，
     * 同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
     *
     * 注意：答案中不可以包含重复的三元组。
     */
    public List<List<Integer>> threeSum(int[] nums) {

        /**
         * 示例 1：
         * 输入：nums = [-1,0,1,2,-1,-4]
         * 输出：[[-1,-1,2],[-1,0,1]]
         * 解释：
         * nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
         * nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
         * nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
         * 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
         * 注意，输出的顺序和三元组的顺序并不重要。
         *
         * 示例 2：
         * 输入：nums = [0,1,1]
         * 输出：[]
         * 解释：唯一可能的三元组和不为 0 。
         *
         * 示例 3：
         * 输入：nums = [0,0,0]
         * 输出：[[0,0,0]]
         * 解释：唯一可能的三元组和为 0 。
         *
         */
        List<List<Integer>> list = new ArrayList<>();
        //1. 数组的个数小于3, 直接返回空数组
        if(nums.length < 3){
            return list;
        }

        //2. 数组的个数等于3, 判断是否满足条件, 满足则返回数组, 否则返回空数组
        if(nums.length == 3){
            if(nums[0] + nums[1] + nums[2] == 0){
                list.add(Arrays.asList(nums[0], nums[1], nums[2]));
            }else{
                return list;
            }
        }

        Arrays.sort(nums);
        //3. 遍历数组中所有的元素, 判断是否满足条件且值是否已经在集合中存在, 满足条件则添加到结果集中
        for(int i = 0; i < nums.length; i++){
            int[] num = new int[3];
            num[0] = nums[i];
            for(int j = i + 1; j < nums.length; j++){
                if(num[1] == nums[j]){
                    continue;
                }
                num[1] = nums[j];
                for(int k = j + 1; k < nums.length; k++){
                    if(num[2] == nums[k]){
                        continue;
                    }
                    num[2] = nums[k];
                    if(i != j && i != k && j != k){
                        if(num[0] + num[1] + num[2] == 0){
                            list.add(Arrays.asList(num[0], num[1], num[2]));
                        }
                    }
                }
            }
        }
        return list;
    }


    public List<List<Integer>> threeSum2(int[] nums) {
        List<List<Integer>> ans = new ArrayList();
        int len = nums.length;
        if(len < 3) return ans;
        Arrays.sort(nums); // 排序
        for (int i = 0; i < len ; i++) {
            if(nums[i] > 0) break; // 如果当前数字大于0，则三数之和一定大于0，所以结束循环
            if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
            int L = i+1;
            int R = len-1;
            while(L < R){
                int sum = nums[i] + nums[L] + nums[R];
                if(sum == 0){
                    ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
                    while (L<R && nums[L] == nums[L+1]) L++; // 去重
                    while (L<R && nums[R] == nums[R-1]) R--; // 去重
                    L++;
                    R--;
                }
                else if (sum < 0) L++;
                else if (sum > 0) R--;
            }
        }
        return ans;
    }
}
